package com.sy.simpleegg.serialport.whmlyy

import android.util.Log
import com.sy.coincontroller.controller.status.SaveFlowStatus
import com.sy.simpleegg.bean.CashConfigBean
import com.sy.simpleegg.ext.logFile
import com.sy.simpleegg.serialport.bean.ComData
import com.sy.simpleegg.serialport.whmlyy.bean.WhmLyyOrderBean
import com.sy.simpleegg.serialport.whmlyy.bean.WhmLyyOutCoinsBean
import com.sy.simpleegg.serialport.whmlyy.bean.WhmLyyOutResultBean
import com.sy.simpleegg.serialport.whmlyy.bean.WhmLyySaveCoinsBean
import com.sy.simpleegg.serialport.whmlyy.bean.WhmLyySaveResult
import com.sy.simpleegg.serialport.whmlyy.bean.WhmLyySaveResultBean
import com.sy.simpleegg.serialport.whmlyy.status.WhmLyyOutFlowStatus
import com.sy.simpleegg.serialport.whmlyy.status.WhmLyyOutResult
import com.sy.simpleegg.util.ByteUtil
import com.sy.simpleegg.util.DateTimeUtil
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.cnbleu.serialport.SerialPort
import java.util.Queue
import java.util.concurrent.LinkedBlockingDeque
import kotlin.random.Random

class WhmLyyController(
    portName: String,
    baudrate: SerialPort.BAUDRATE,
    stopb: SerialPort.STOPB,
    datab: SerialPort.DATAB,
    parity: SerialPort.PARITY,
    runHeartBeat: Boolean,
    private val whmLyyListener: WhmLyyListener?,
    speed: Long = 10L
): BaseWhmLyyController(portName, baudrate, stopb, datab, parity, speed) {

    private var charArr = arrayOf("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "B", "C", "E", "F")

    private var default_timeout = 10*1000
    private var save_timeout = 62*1000

    private var currentOutCoinsBean: WhmLyyOutCoinsBean? = null
    private var currentSaveCoinsBean: WhmLyySaveCoinsBean? = null

    /**
     * 协程
     */
    private var coroutineScope: CoroutineScope? = null
    /**
     * 控制板心跳线程
     */
    private var heartBeatJob: Job? = null

    private val orderQueue: Queue<WhmLyyOrderBean> = LinkedBlockingDeque<WhmLyyOrderBean>()
    private var handleJob: Job? = null
    private var isLoop = true
    private var heartLoop = true

    private var outResp = false
    private var handling = false

    /**
     * 心跳间隔，正常-10秒 异常-3秒
     */
    private val HEARTBEAT_INTERVAL_CONNECT: Long = 10 * 1000
    /**
     * 心跳间隔，正常-10秒 异常-3秒
     */
    private val HEARTBEAT_INTERVAL_DISCONNECT: Long = 3 * 1000

    /**
     * 链接状态
     */
    private var isConnect = false
    /**
     * 心跳响应状态，发心跳指令前先设置为false，收到心跳响应设置为true
     */
    private var state: Boolean = true
    private var stateCode = 0
    private var errCode = 0

    private var whmLyyOutFlowStatus = WhmLyyOutFlowStatus.PREPARE
    private var saveFlowStatus = SaveFlowStatus.PREPARE

    private var errMsg = ""

    init {
        logFile("打开whm_lyy协议版本控制板，串口号=$portName 波特率=$baudrate 停止位=$stopb 数据位=$datab 校验位=$parity 控制板心跳：${if (runHeartBeat) "开启" else "关闭"}")
        coroutineScope = MainScope()
        initHandleJob()
        if (runHeartBeat) heartBeatLoop()

        /**
         * 获取控制板配置，设置默认值
         */
        coroutineScope?.launch(Dispatchers.IO) {
            do {
                delay(1000)
                getTerminalConfig()
            }while (!isConnect)
        }
    }

    fun getConnectState(): Boolean{
        return isConnect
    }

    private fun initHandleJob(){
        handleJob?.cancel()

        handleJob = coroutineScope?.launch (Dispatchers.IO){
            while (isLoop){
                try {
                    run checkSize@{
                        if (orderQueue.size > 0 && !handling) {
                            var orderBean: WhmLyyOrderBean? = null
                            while (orderQueue.poll().also { orderBean = it } != null) {
                                handling = true
                                val sn = orderBean!!.sn
                                val amount = orderBean!!.amount
                                val coins = orderBean!!.coins
                                val type = orderBean!!.type
                                val userId = orderBean!!.userId

                                if (!isConnect){
//                                    serialControllerListener.onOutCoinsErr()
                                    handling = false
                                    return@checkSize
                                }

                                when (type){
                                    1 -> {
                                        val result = outCoinsHandler(sn, amount, coins)

                                        result.outCoinsBean?.let {
                                            val remainCount = it.needOutCoins - it.realOutCoins
                                            withContext(Dispatchers.Main){
                                                whmLyyListener?.outCoinFinish(remainCount, it.realOutCoins, true)
                                                whmLyyListener?.onOutResult(when (result.resultCode){
                                                    WhmLyyOutResult.COMPLETED -> "出币完成"
                                                    WhmLyyOutResult.REFUSE -> "拒绝出币"
                                                    WhmLyyOutResult.ERROR -> "出币异常"
                                                    WhmLyyOutResult.TIMEOUT -> "出币超时"
                                                })
                                            }
                                        }

//                                        when (result.resultCode){
//                                            OutResult.COMPLETED -> {}
//                                            OutResult.REFUSE -> {}
//                                            OutResult.ERROR -> {}
//                                            OutResult.TIMEOUT -> {}
//                                        }
                                    }
                                    2 -> {
                                        val saveResult = saveCoinsHandler(userId)
                                        saveResult.saveCoinsBean?.let {
                                            whmLyyListener?.saveCoinFinish(it.saveCoins, it.snHex, it.userId)
                                        }
//
                                        when (saveResult.resultCode){
                                            WhmLyySaveResult.FINISH -> {}
                                            WhmLyySaveResult.TIMEOUT -> {
                                                saveClose(currentSaveCoinsBean!!.snHex)
                                            }
                                            WhmLyySaveResult.ERROR -> {
                                                saveClose(currentSaveCoinsBean!!.snHex)
                                            }
                                        }
                                        currentSaveCoinsBean = null
                                    }
                                    3 -> {
                                        val clearResult = clearCoinsHandler(sn, amount, coins)
                                        val realOutCoins = clearResult.outCoinsBean!!.realOutCoins
                                        refreshClearCoins(true, realOutCoins)
                                    }
                                    else -> {

                                    }
                                }

                                handling = false
                            }
                        }
                    }
                }catch (e: Exception){
                    e.printStackTrace()
                    logFile("处理出币点单异常：${e.message}")
                }
            }
        }
    }

    /**
     * 心跳
     */
    private fun heartBeatLoop(){
        try {
            heartBeatJob?.cancel()

            heartBeatJob = coroutineScope?.launch (Dispatchers.IO){
                try {
                    run breaking@{
                        while (heartLoop){
                            //出币中，不发送心跳指令，直接返回心跳正常
                            if (handling) {
//                                isConnect = true
                                whmLyyListener?.heartBeat(isConnect, stateCode, errCode)
                                delay(5000)
                                return@breaking
                            }

                            state = true
                            checkState()
                            delay(500)
                            isConnect = !state
                            whmLyyListener?.heartBeat(isConnect, stateCode, errCode)

                            if (state){
                                delay(HEARTBEAT_INTERVAL_DISCONNECT)
                            }else{
                                delay(HEARTBEAT_INTERVAL_CONNECT)
                            }
                        }
                    }
                }catch (e: Exception){
                    e.printStackTrace()
                    logFile("心跳处理异常2：" + e.message)
                }
            }
        }catch (e: Exception){
            e.printStackTrace()
            logFile("心跳处理异常：" + e.message)
        }
    }

    /**
     * 出币处理
     */
    private suspend fun outCoinsHandler(sn: String, amount: Long, coins: Long): WhmLyyOutResultBean {
        return try {
            //指令响应超时
            var overCount = 0
            val interval = 80L
            val maxCount = default_timeout / interval
            var outFinish = false

            currentOutCoinsBean = WhmLyyOutCoinsBean(sn, WhmLyyOutFlowStatus.PREPARE, amount, 0, coins)

            whmLyyOutFlowStatus = WhmLyyOutFlowStatus.PREPARE

            val uniqueCode = unRepeatSixCode()

            transferPrepare(uniqueCode)

            val prepare = run prepare@{
                while (true){
                    delay(interval)
                    overCount ++
                    when (whmLyyOutFlowStatus){
                        WhmLyyOutFlowStatus.PREPARE_FINISH -> {
                            return@prepare true
                        }
                        else -> {}
                    }
                    if (overCount >= maxCount){
                        whmLyyOutFlowStatus = WhmLyyOutFlowStatus.TIMEOUT
                        return@prepare false
                    }
                }
            }
            val prepareResult = prepare as Boolean
            if (!prepareResult){
                return WhmLyyOutResultBean(WhmLyyOutResult.TIMEOUT, currentOutCoinsBean)
            }

            overCount = 0

            var lastOutCoins = -1L

            outCoin(coins, amount, sn, uniqueCode)

            val result = run result@{
                while (true){
                    delay(interval)
                    overCount ++
                    when (whmLyyOutFlowStatus){
                        WhmLyyOutFlowStatus.PREPARE -> {

                        }
                        WhmLyyOutFlowStatus.PREPARE_FINISH -> {

                        }
                        WhmLyyOutFlowStatus.REC -> {
                            currentOutCoinsBean?.run {
                                snFlowStatus = WhmLyyOutFlowStatus.REC
                            }
                        }
                        WhmLyyOutFlowStatus.RESP -> {
                            currentOutCoinsBean?.run {
                                if (lastOutCoins != realOutCoins){
                                    overCount = 0
                                    lastOutCoins = realOutCoins
                                    refreshOutCoins(realOutCoins)
                                }
                            }
                        }
                        WhmLyyOutFlowStatus.FINISH -> {
                            outFinish = true
                            return@result WhmLyyOutResult.COMPLETED
                        }
                        WhmLyyOutFlowStatus.TIMEOUT -> {
                            outFinish = true
                            return@result WhmLyyOutResult.TIMEOUT
                        }
                        WhmLyyOutFlowStatus.ERROR -> {
                            outFinish = true
                            return@result WhmLyyOutResult.ERROR
                        }
                    }

                    if (!outFinish && overCount >= maxCount){
                        whmLyyOutFlowStatus = WhmLyyOutFlowStatus.TIMEOUT
                        return@result WhmLyyOutResult.TIMEOUT
                    }
                }
                WhmLyyOutResult.TIMEOUT
            }

            return WhmLyyOutResultBean(result, currentOutCoinsBean)
        }catch (e: Exception){
            e.printStackTrace()
            logFile("出币流程异常：" + e.message)
            WhmLyyOutResultBean(WhmLyyOutResult.ERROR, null)
        }
    }

    /**
     * 存币处理
     */
    private suspend fun saveCoinsHandler(userId: String): WhmLyySaveResultBean {
        return try {
            //指令响应超时
            var overCount = 0
            val interval = 500L
            val maxCount = save_timeout / interval
            var isRec = false

            saveFlowStatus = SaveFlowStatus.PREPARE

            val userIdHex = ByteUtil.str2HexString(userId)
            currentSaveCoinsBean = WhmLyySaveCoinsBean(getSnHex(), userIdHex, 0)

            var lastSaveCoins = -1L

            saveOpen(currentSaveCoinsBean!!.snHex, currentSaveCoinsBean!!.userId)

            val result = run result@{
                while (true){
                    delay(interval)
                    overCount ++
                    when (saveFlowStatus){
                        SaveFlowStatus.PREPARE -> {
                            if (overCount >= maxCount){
                                return@result WhmLyySaveResult.TIMEOUT
                            }
                        }
                        SaveFlowStatus.REC -> {
                            if (isRec){
                                overCount ++
                            }else{
                                isRec = true
                                overCount = 0
                                currentSaveCoinsBean?.let {
                                    refreshSaveCoins(false, it.saveCoins)
                                }
                            }
                        }
                        SaveFlowStatus.RESP -> {
                            currentSaveCoinsBean?.let {
                                if (lastSaveCoins != it.saveCoins){
                                    overCount = 0
                                    lastSaveCoins = it.saveCoins
                                    refreshSaveCoins(false, it.saveCoins)
                                }else{
                                    overCount ++
                                }
                            }
                        }

                        SaveFlowStatus.FINISH -> {
                            currentSaveCoinsBean?.let {
                                refreshSaveCoins(true, it.saveCoins)
                            }
                            return@result WhmLyySaveResult.FINISH
                        }
                    }

                    if (overCount >= maxCount){
                        return@result WhmLyySaveResult.TIMEOUT
                    }
                }
                WhmLyySaveResult.TIMEOUT
            }

            return WhmLyySaveResultBean(result, currentSaveCoinsBean)
        }catch (e: Exception){
            e.printStackTrace()
            logFile("存币流程异常：" + e.message)
            WhmLyySaveResultBean(WhmLyySaveResult.ERROR, null)
        }
    }

    /**
     * 清币处理
     */
    private suspend fun clearCoinsHandler(sn: String, amount: Long, coins: Long): WhmLyyOutResultBean {
        return try {
            //指令响应超时
            var overCount = 0
            val interval = 100L
            val maxCount = default_timeout / interval
            var outFinish = false

            currentOutCoinsBean = WhmLyyOutCoinsBean(sn, WhmLyyOutFlowStatus.PREPARE, amount, 0, coins)

            whmLyyOutFlowStatus = WhmLyyOutFlowStatus.PREPARE

            val uniqueCode = unRepeatSixCode()

            transferPrepare(uniqueCode)

            val prepare = run prepare@{
                while (true){
                    delay(interval)
                    overCount ++
                    when (whmLyyOutFlowStatus){
                        WhmLyyOutFlowStatus.PREPARE_FINISH -> {
                            return@prepare true
                        }
                        else -> {}
                    }
                    if (overCount >= maxCount){
                        whmLyyOutFlowStatus = WhmLyyOutFlowStatus.TIMEOUT
                        return@prepare false
                    }
                }
            }
            val prepareResult = prepare as Boolean
            if (!prepareResult){
                return WhmLyyOutResultBean(WhmLyyOutResult.TIMEOUT, currentOutCoinsBean)
            }

            overCount = 0

            var lastOutCoins = -1L

            outCoin(coins, amount, sn, uniqueCode)

            val result = run result@{
                while (true){
                    delay(interval)
                    overCount ++
                    when (whmLyyOutFlowStatus){
                        WhmLyyOutFlowStatus.PREPARE -> {

                        }
                        WhmLyyOutFlowStatus.PREPARE_FINISH -> {

                        }
                        WhmLyyOutFlowStatus.REC -> {
                            currentOutCoinsBean?.run {
                                snFlowStatus = WhmLyyOutFlowStatus.REC
                            }
                        }
                        WhmLyyOutFlowStatus.RESP -> {
                            currentOutCoinsBean?.run {
                                if (lastOutCoins != realOutCoins){
                                    overCount = 0
                                    lastOutCoins = realOutCoins
                                    refreshClearCoins(false, realOutCoins)
                                }
                            }
                        }
                        WhmLyyOutFlowStatus.FINISH -> {
                            outFinish = true
                            return@result WhmLyyOutResult.COMPLETED
                        }
                        WhmLyyOutFlowStatus.TIMEOUT -> {
                            outFinish = true
                            return@result WhmLyyOutResult.TIMEOUT
                        }
                        WhmLyyOutFlowStatus.ERROR -> {
                            outFinish = true
                            return@result WhmLyyOutResult.ERROR
                        }
                    }

                    if (!outFinish && overCount >= maxCount){
                        whmLyyOutFlowStatus = WhmLyyOutFlowStatus.TIMEOUT
                        return@result WhmLyyOutResult.TIMEOUT
                    }
                }
                WhmLyyOutResult.TIMEOUT
            }

            return WhmLyyOutResultBean(result, currentOutCoinsBean)
        }catch (e: Exception){
            e.printStackTrace()
            logFile("清币流程异常：" + e.message)
            WhmLyyOutResultBean(WhmLyyOutResult.ERROR, null)
        }
    }

    private suspend fun refreshOutCoins(realOutCoins: Long){
        withContext(Dispatchers.Main){
            whmLyyListener?.onCoinRefresh(currentOutCoinsBean?.needOutCoins?:0, realOutCoins, true)
        }
    }

    private suspend fun refreshSaveCoins(finish: Boolean, saveCoins: Long){
        withContext(Dispatchers.Main){
            whmLyyListener?.onCoinRefresh(-1, saveCoins, false)
        }
    }

    private suspend fun refreshClearCoins(isFinish: Boolean, realOutCoins: Long){
        withContext(Dispatchers.Main){
            whmLyyListener?.onClearCoin(isFinish, realOutCoins)
        }
    }

    fun outCoins(coins: Long, amount: Long, sn: String, uniqueCode: String){
        if (handling){
            return
        }
        orderQueue.add(WhmLyyOrderBean(sn, coins, amount, 1))
    }

    fun saveCoins(sn: String, userIdHex: String){
        if (handling){
            return
        }
        orderQueue.add(WhmLyyOrderBean(sn, 0, 0, 2, userIdHex))
    }

    /**
     * 关闭存币
     */
    fun saveFinish(){
        currentSaveCoinsBean?.let {
            saveClose(it.snHex)
        }
    }

    fun clearCoins(){
        if (handling){
            return
        }
        val coins = 65535L
        orderQueue.add(WhmLyyOrderBean(getSn(), coins, 0, 3))
    }

    fun setCashConfig(cashConfigBean: CashConfigBean){
        var configHex = ""
        cashConfigBean.run {
            configHex = "$configHex${if (channel1Enable) {ByteUtil.long2HexStr(channel1Coins, 4, true)} else {"0000"}}"
            configHex = "$configHex${if (channel2Enable) {ByteUtil.long2HexStr(channel2Coins, 4, true)} else {"0000"}}"
            configHex = "$configHex${if (channel3Enable) {ByteUtil.long2HexStr(channel3Coins, 4, true)} else {"0000"}}"
            configHex = "$configHex${if (channel4Enable) {ByteUtil.long2HexStr(channel4Coins, 4, true)} else {"0000"}}"
            configHex = "$configHex${if (channel5Enable) {ByteUtil.long2HexStr(channel5Coins, 4, true)} else {"0000"}}"
            configHex = "$configHex${if (channel6Enable) {ByteUtil.long2HexStr(channel6Coins, 4, true)} else {"0000"}}"
            configHex = "$configHex${if (channel7Enable) {ByteUtil.long2HexStr(channel7Coins, 4, true)} else {"0000"}}"
            configHex = "$configHex${if (channel8Enable) {ByteUtil.long2HexStr(channel8Coins, 4, true)} else {"0000"}}"
            configHex = "$configHex${if (channel9Enable) {ByteUtil.long2HexStr(channel9Coins, 4, true)} else {"0000"}}"
            configHex = "$configHex${if (channel10Enable) {ByteUtil.long2HexStr(channel10Coins, 4, true)} else {"0000"}}"
        }
        setCashConfig(configHex)
    }

    fun resetMotor(){
        setMotor(0, 0)
    }

    fun release(){
        try {
            releaseBase()
            isLoop = false
            heartLoop = false
            heartBeatJob?.cancel()
            handleJob?.cancel()
            coroutineScope?.cancel()
        }catch (e: Exception){
            e.printStackTrace()
        }
    }

    fun getSn(): String {
        return try {
            val date = DateTimeUtil.nowDateTime
            val result = date.substring(date.length - 8)
            Log.d(javaClass.simpleName, "sn：$result")
            result
        }catch (e: Exception){
            e.printStackTrace()
            "aaaaaaaa"
        }
    }

    private fun getSnHex(): String{
        var snHex = ""
        for (i in 0..7){
            val random = Random.nextInt(charArr.size)
            snHex += charArr[random]
        }
        return snHex
    }

    override fun onRecHeartBeat() {
        state = false
    }

    override fun onRecCash(
        addCode: Int,
        errCodeHex: String,
        cash: String,
        outCoins: String,
        donateCoins: String,
        descHex: String
    ) {
        logFile("收到上报账目数据")
        whmLyyListener?.onRecCash(addCode, errCodeHex, cash, outCoins, donateCoins, descHex)
    }

    override fun onRecCashConfig(configHex: String) {
        logFile("收到纸钞机配置")
        whmLyyListener?.onRecCashConfig(configHex)
    }

    override fun onRecMotorConfig(configHex: String) {
        logFile("收到马达配置")
        whmLyyListener?.onRecMotorConfig(configHex)
    }

    override fun onRecPrepare(online: Boolean) {
        logFile("收到出币订单")
        whmLyyOutFlowStatus = WhmLyyOutFlowStatus.PREPARE_FINISH
    }

    override fun onRecStart(success: Int, msg: String) {
        logFile("出币启动状态：$success $msg")
        if (success == 0) {
            whmLyyOutFlowStatus = WhmLyyOutFlowStatus.REC
        }else{
            errMsg = msg
            whmLyyOutFlowStatus = WhmLyyOutFlowStatus.ERROR
        }
    }

    override fun onRecOutCoinFinish(success: Int, msg: String) {
        logFile("出币结束：$success $msg")
        if (success == 0) {
            whmLyyOutFlowStatus = WhmLyyOutFlowStatus.FINISH
        }else{
            errMsg = msg
            whmLyyOutFlowStatus = WhmLyyOutFlowStatus.ERROR
        }
    }

    override fun onRecOutCoinInfo(amount: Long, needOutCoins: Long, remainOutCoins: Long) {
        logFile("出币信息：$amount $needOutCoins $remainOutCoins")
        whmLyyOutFlowStatus = WhmLyyOutFlowStatus.RESP
        currentOutCoinsBean?.let {
            it.amount = amount
            it.needOutCoins = needOutCoins
            it.realOutCoins = needOutCoins - remainOutCoins
            it.snFlowStatus = WhmLyyOutFlowStatus.RESP
        }
    }

    override fun onRecTerminalConfig(configHex: String) {
        logFile("收到终端配置")
        whmLyyListener?.onRecBasicConfig(configHex)
    }

    override fun onRecSetTerminalResult(success: Boolean) {
        logFile("设置终端配置${if (success) "成功" else "失败"}")
    }

    override fun onSavePrepare(prepare: Boolean, userIdHex: String) {
        logFile("存币启动响应：存币启动${if (prepare) "成功" else "失败"} 用户ID：$userIdHex")
        saveFlowStatus = SaveFlowStatus.REC
    }

    override fun onSaveInfo(snHex: String, saveCoins: Long) {
        logFile("存币数：$saveCoins")
        saveFlowStatus = SaveFlowStatus.RESP
        currentSaveCoinsBean?.saveCoins = saveCoins
    }

    override fun onSaveFinish(snHex: String, saveCoins: Long) {
        logFile("存币结束：$saveCoins")
        saveFlowStatus = SaveFlowStatus.FINISH
        currentSaveCoinsBean?.saveCoins = saveCoins
    }

    override fun cmdTimeout(comData: ComData) {
        logFile("指令超时")
        whmLyyListener?.onCmdTimeout(comData)
    }

//    override fun sendCmd(msg: String) {
//        logFile("发送指令：$msg")
//        transferListener?.onSendCmd(msg)
//    }

    interface WhmLyyListener{
        /**
         * 心跳数据回调
         */
        fun heartBeat(isConnect: Boolean, stateCode: Int, errCode: Int)

        /**
         * 上报账目数据
         * @param addCode 自增码
         * @param errCodeHex 故障代码
         * @param cash 营收增量（只有投了现金才上报，单位元）
         * @param outCoins 出币增量
         * @param donateCoins 增币
         * @param descHex 预留数据
         */
        fun onRecCash(addCode: Int, errCodeHex: String, cash: String, outCoins: String, donateCoins: String, descHex: String)

        /**
         * 收到基础配置
         */
        fun onRecBasicConfig(configHex: String)

        /**
         * 收到纸钞配置
         */
        fun onRecCashConfig(configHex: String)

        /**
         * 收到马达配置
         */
        fun onRecMotorConfig(configHex: String)
        /**
         * 刷新出币或存币数据
         */
        fun onCoinRefresh(needOutCoins: Long, coinCount: Long, outOrSave: Boolean)
        /**
         * 清币回调
         */
        fun onClearCoin(clearFinish: Boolean, clearCoinCount: Long)
        /**
         * 出币数据回调
         */
        fun outCoinFinish(remainCount: Long, currentOutCount: Long, outFinish: Boolean)
        /**
         * 存币结束回调
         * @param saveCoins 存币数
         * @param snHex 订单
         * @param userIdHex 用户id
         */
        fun saveCoinFinish(saveCoins: Long, snHex: String, userIdHex: String)
        /**
         * 出币结果
         */
        fun onOutResult(msg: String)
        fun onCmdTimeout(comData: ComData)
        fun onSendCmd(msg: String)
    }
}